package config

import (
	"fmt"
	"github.com/mitchellh/mapstructure"
	"github.com/spf13/viper"
	"os"
)

type Conf struct {
	SourceUrl       string // 源端链接
	TargetUrl       string // 目标端链接
	MaxConnPool     int    `default:"100"`  // 连接池数量
	MaxConnIdlePool int    `default:"10"`   // 闲置连接池数量
	ParallelT       int    `default:"10"`   // 表级别并行数量
	PalallelS       int    `default:"10"`   // 表内并行数量
	ChunkSize       int    `default:"1000"` // 查询块大小
	Delay           int    `default:"0"`    // 目标端为源端异地灾备时，预估的延迟时间，单位秒，不是异地灾备，不要设置该参数
	//ChannelSize     int     `default:"100"`  // 校验通道大小
	LogLevel int `default:"info"` // 日志级别

	Interval   int64   // 命令行日志输出频率
	LogDir     string  // 日志路径
	TableArray []Table // 表数组
	Schema     string  // 表所属schema
	Checksum   string  // 校验模式，取值：data/struct

	// Grid新增
	SDataServer string // shard节点名称，主从节点均可
	TDataServer string // shard节点名称，主从节点均可
	Database    string // 表所属shard上schema
	GridFlag    bool   // 通过grid节点（代理节点）连接数据库
}

type Table struct {
	Tablename    string `json:"tablename"`    // 表名
	SplitColumn  string `json:"splitcolumn"`  // 切分列列名
	ValueColumnK string `json:"valuecolumnk"` // 指定值列列名
	ValueColumnV string `json:"valuecolumnv"` // 指定值列列值
	PalallelS    int    `json:"parallels"`    // 表内并行度，优先于全局参数
	ChunkSize    int    `json:"chunksize"`    // 表内查询块大小，优先于全局参数
	Partition    string `json:"partition"`    // 分区名
}

func ReadConf(path string, name string, tp string) Conf {
	var conf Conf
	config := viper.New()
	config.AddConfigPath(path)
	config.SetConfigName(name)
	config.SetConfigType(tp)

	if err := config.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			fmt.Println("Can not find conf file...")
			os.Exit(1)
		} else {
			fmt.Println("Conf file format error...")
			os.Exit(1)
		}
	}

	conf.SourceUrl = config.GetString("sourceurl")
	conf.TargetUrl = config.GetString("targeturl")
	if conf.SourceUrl == "" || conf.TargetUrl == "" {
		fmt.Println("Check need sourceurl/targeturl value in conf file...")
		os.Exit(1)
	}

	conf.MaxConnPool = config.GetInt("maxconnpool")
	if conf.MaxConnPool == 0 {
		conf.MaxConnPool = 100
	}
	conf.MaxConnIdlePool = config.GetInt("maxconnidlepool")
	if conf.MaxConnIdlePool == 0 {
		conf.MaxConnIdlePool = 10
	}
	conf.ParallelT = config.GetInt("parallelt")
	if conf.ParallelT == 0 {
		conf.ParallelT = 10
	}
	conf.PalallelS = config.GetInt("palallels")
	if conf.PalallelS == 0 {
		conf.PalallelS = 10
	}
	conf.ChunkSize = config.GetInt("chunksize")
	if conf.ChunkSize == 0 {
		conf.ChunkSize = 1000
	}
	conf.Delay = config.GetInt("delay")
	conf.Interval = config.GetInt64("interval")
	if conf.Interval == 0 {
		conf.Interval = 1
	}

	var le = config.GetString("loglevel")
	switch le {
	case "error":
		conf.LogLevel = 8
	case "warn":
		conf.LogLevel = 4
	case "info":
		conf.LogLevel = 0
	case "debug":
		conf.LogLevel = -4
	default:
		fmt.Println("Log level error, value range: error, warn, info, debug...")
		os.Exit(1)
	}
	conf.LogDir = config.GetString("logdir")
	conf.Schema = config.GetString("schema")
	if conf.Schema == "" {
		fmt.Println("Check need schema value in conf file...")
		os.Exit(1)
	}
	conf.Checksum = config.GetString("checksum")
	if conf.Checksum == "" {
		conf.Checksum = "data"
		fmt.Println("checksum not found in conf file")
	}

	// grid 新增
	conf.SDataServer = config.GetString("sdataserver")
	conf.TDataServer = config.GetString("tdataserver")
	conf.Database = config.GetString("database")

	gfTem := config.GetString("gridflag")
	if gfTem == "" {
		conf.GridFlag = true // 默认连接grid做校验
	} else {
		if gfTem == "true" {
			conf.GridFlag = true
		} else if gfTem == "false" {
			conf.GridFlag = false
		} else {
			conf.GridFlag = true
		}
	}
	if conf.GridFlag && conf.Database == "" {
		fmt.Println("Check need database value in conf file...")
		os.Exit(1)
	}

	tTables := config.Get("tables")
	tables, aok := tTables.([]interface{})
	if !aok {
		fmt.Println("Error occur when read conf file...")
		os.Exit(1)
	}
	for _, v := range tables {
		table, tok := v.(map[string]interface{})
		if !tok {
			fmt.Println("Error occur when read conf file...")
			os.Exit(1)
		}
		var tb Table
		err := mapstructure.Decode(table, &tb)
		if err != nil {
			fmt.Println(err.Error())
		}
		conf.TableArray = append(conf.TableArray, tb)
	}
	return conf
}
